package com.ztc.view;

import javax.sound.midi.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by ztc on 15-11-24.
 */
public class display extends JFrame {
    JPanel center,move;
    Box buttonBox,nameBox;
    JButton start,stop,up,down,save,open,clear;
    JFileChooser jfc;
    List<JCheckBox> checkBox;
    Sequencer sequencer;
    Sequence sequence;
    Track track;
    String[] typeName={"Bass Drum","Closed Hi-Hat","Open Hi-Hat",
                        "Acoustic Snare","Crash Cymbal","Hand Clap",
                        "High Tom","Hi Bongo","Maracas","Whistle","Low Conga",
                        "Cowbell","Vibraslap","Low-mid Tom","High Agogo",
                        "Open Hi Conga"};
    int[] type={35,42,46,38,49,39,50,60,70,72,64,56,58,47,67,63};
    public static void main(String[] args){
        new display();
    }
    public display(){
        jfc=new JFileChooser("./");
        //左部
        nameBox=new Box(BoxLayout.Y_AXIS);
        for(int i=0;i<16;i++){
            nameBox.add(new JLabel(typeName[i]));
        }
        this.add(nameBox,"West");
        //右部
        buttonBox=new Box(BoxLayout.Y_AXIS);
        start=new JButton("Start");
        start.addActionListener(new MyStartListener());
        stop=new JButton("Stop");
        stop.addActionListener(new MyStopListener());
        up=new JButton("Up");
        up.addActionListener(new MyUpListener());
        down=new JButton("Down");
        down.addActionListener(new MyDownListener());
        save=new JButton("Save");
        save.addActionListener(new MySaveListener(this));
        open=new JButton("Open");
        open.addActionListener(new MyOpenListener(this));
        clear=new JButton("Clear");
        clear.addActionListener(new MyClearListener());
        buttonBox.add(start);
        buttonBox.add(stop);
        buttonBox.add(up);
        buttonBox.add(down);
        buttonBox.add(save);
        buttonBox.add(open);
        buttonBox.add(clear);
        this.add(buttonBox, "East");
        //中部
        checkBox=new ArrayList<JCheckBox>();
        center=new JPanel();
        center.setLayout(new GridLayout(16,16,2,2));
        for(int i=0;i<256;i++){
            JCheckBox c=new JCheckBox();
            c.setSelected(false);
            checkBox.add(c);
            center.add(c);
        }
        this.add(center,"Center");

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(500,280);
        this.setLocation(500,300);
        this.setVisible(true);
        this.setTitle("BeatBox");


        try {
            sequencer= MidiSystem.getSequencer();
            sequencer.open();
            sequence=new Sequence(Sequence.PPQ,4);
            track=sequence.createTrack();
            sequencer.setTempoInBPM(120);
        } catch (MidiUnavailableException e) {
            e.printStackTrace();
        } catch (InvalidMidiDataException e) {
            e.printStackTrace();
        }

    }


    public void makeTracks(int[] list){
        for(int i=0;i<16;i++){
            if(list[i]!=0){
                track.add(makeEvent(144,9,list[i],100,i));
                track.add(makeEvent(128,9,list[i],100,i+1));
            }
        }
    }

    public MidiEvent makeEvent(int comd,int chan,int one,int two,int tick){
        MidiEvent event=null;
        try {
            ShortMessage b=new ShortMessage();
            b.setMessage(comd, chan, one, two);
            event=new MidiEvent(b,tick);
        } catch (InvalidMidiDataException e) {
            e.printStackTrace();
        }
        return event;
    }
    public void buildTrackAndStart(){
        int[] trackList=null;
        sequence.deleteTrack(track);
        track=sequence.createTrack();
        for(int i=0;i<16;i++){
            trackList=new int[16];
            for(int j=0;j<16;j++){
                JCheckBox jc=(JCheckBox)checkBox.get(j+(16*i));
                if(jc.isSelected()){
                    trackList[j]=type[i];
                }else{
                    trackList[j]=0;
                }
            }
            makeTracks(trackList);
            track.add(makeEvent(176,1,126,0,16));
        }


        try {
            track.add(makeEvent(192,9,1,0,15));
            sequencer.setSequence(sequence);
            sequencer.setLoopCount(sequencer.LOOP_CONTINUOUSLY);
            sequencer.start();
            sequencer.setTempoInBPM(120);
        } catch (InvalidMidiDataException e) {
            e.printStackTrace();
        }
    }

    private class MyStartListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            buildTrackAndStart();
        }
    }

    private class MyStopListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            sequencer.stop();
        }
    }

    private class MyDownListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            float tempoFactor=sequencer.getTempoFactor();
            sequencer.setTempoFactor((float)(tempoFactor*0.97));
        }
    }

    private class MyUpListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            float tempoFactor=sequencer.getTempoFactor();
            sequencer.setTempoFactor((float)(tempoFactor*1.03));
        }
    }

    private class MySaveListener implements ActionListener {
        JFrame jf;
        public MySaveListener(JFrame jf){
            this.jf=jf;
        }
        @Override
        public void actionPerformed(ActionEvent e) {
            jfc.setCurrentDirectory(jfc.getCurrentDirectory());
            int result=jfc.showSaveDialog(jf);
            File f=jfc.getSelectedFile();
            boolean[] o=new boolean[256];
            for(int i=0;i<256;i++){
                if(((JCheckBox)checkBox.get(i)).isSelected()){
                    o[i]=true;
                }
            }
            if(result==0&&f!=null) {
                try {
                    FileOutputStream fos = new FileOutputStream(f);
                    ObjectOutputStream oos = new ObjectOutputStream(fos);
                    oos.writeObject(o);
                } catch (FileNotFoundException e1) {
                    e1.printStackTrace();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    private class MyOpenListener implements ActionListener {
        JFrame jf;
        public MyOpenListener(JFrame jf) {
            this.jf=jf;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            jfc.setCurrentDirectory(jfc.getCurrentDirectory());
            int result=jfc.showOpenDialog(jf);
            File f=jfc.getSelectedFile();
            if(result==0&&f!=null) {
                try {
                    FileInputStream fis = new FileInputStream(f);
                    ObjectInputStream ois = new ObjectInputStream(fis);
                    boolean[] o = (boolean[]) ois.readObject();
                    for (int i = 0; i < 256; i++) {
                        if (o[i]) {
                            checkBox.get(i).setSelected(true);
                        } else {
                            checkBox.get(i).setSelected(false);
                        }
                    }
                    sequencer.stop();
                    //buildTrackAndStart();
                } catch (FileNotFoundException e1) {
                    e1.printStackTrace();
                } catch (IOException e1) {
                    e1.printStackTrace();
                } catch (ClassNotFoundException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    private class MyClearListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            for(int i=0;i<256;i++){
                checkBox.get(i).setSelected(false);
            }
            sequencer.stop();
        }
    }
}
